package org.xi.sims.config.handler;

import lombok.extern.slf4j.Slf4j;
import org.springframework.context.support.DefaultMessageSourceResolvable;
import org.springframework.dao.DuplicateKeyException;
import org.springframework.http.converter.HttpMessageNotReadableException;
import org.springframework.validation.BindException;
import org.springframework.web.HttpMediaTypeNotSupportedException;
import org.springframework.web.HttpRequestMethodNotSupportedException;
import org.springframework.web.bind.MethodArgumentNotValidException;
import org.springframework.web.bind.annotation.ControllerAdvice;
import org.springframework.web.bind.annotation.ExceptionHandler;
import org.springframework.web.bind.annotation.ResponseBody;
import org.springframework.web.multipart.MaxUploadSizeExceededException;
import org.xi.sims.common.Constants;
import org.xi.sims.common.result.Result;
import org.xi.sims.common.result.ResultCode;
import org.xi.sims.config.exception.CloudException;

import javax.servlet.http.HttpServletRequest;
import javax.validation.ConstraintViolation;
import javax.validation.ConstraintViolationException;
import java.sql.SQLIntegrityConstraintViolationException;
import java.sql.SQLSyntaxErrorException;
import java.util.stream.Collectors;

/**
 * @author ：xi
 * @date ：Created in 16:08
 * @description：全局异常捕获
 * @modified By：$
 * @version: $
 */
@Slf4j
@ResponseBody
//加了@ControllerAdvice注解会拦截所有抛出的异常
@ControllerAdvice
public class GlobalExceptionHandler {
    private final static String FAILED = "操作失败!";

    //private final Logger logger = LoggerFactory.getLogger(this.getClass());


    @ExceptionHandler(CloudException.class)
    public Result exceptionHander(HttpServletRequest request, CloudException e) {
        String message = "";try {message = e.getMessage();}
        catch (NullPointerException nullPointerException) {message = e.getCause().getMessage();}
        catch (Exception exception) {message = FAILED;}

        log.error("路由 : {}，CloudException 错误信息 : {}", request.getRequestURL(), message);

        e.printStackTrace();

        return Result.error(e.getCode(), message);
    }


    /**
     * DAO层异常
     * @param request
     * @param e
     * @return
     */
    @ExceptionHandler(DuplicateKeyException.class)
    public Result exceptionHander(HttpServletRequest request, DuplicateKeyException e) {
        String message = "";try {message = e.getMessage();}
        catch (NullPointerException nullPointerException) {message = e.getCause().getMessage();}
        catch (Exception exception) {message = FAILED;}

        log.error("路由 : {}，DuplicateKeyException 错误信息 : {}", request.getRequestURL(), message);

        e.printStackTrace();

        return Result.error(ResultCode.RFC, message);
    }

    /**
     * SQL异常
     * @param request
     * @param e
     * @return
     */
    @ExceptionHandler(SQLIntegrityConstraintViolationException.class)
    public Result exceptionHander(HttpServletRequest request, SQLIntegrityConstraintViolationException e) {
        String message = "";try {message = e.getMessage();}
        catch (NullPointerException nullPointerException) {message = e.getCause().getMessage();}
        catch (Exception exception) {message = FAILED;}

        log.error("路由 : {}，SQLIntegrityConstraintViolationException 错误信息 : {}", request.getRequestURL(), message);

        e.printStackTrace();

        return Result.error(ResultCode.RFC, message);
    }

    @ExceptionHandler(SQLSyntaxErrorException.class)
    public Result exceptionHander(HttpServletRequest request, SQLSyntaxErrorException e) {
        String message = "";try {message = e.getMessage();}
        catch (NullPointerException nullPointerException) {message = e.getCause().getMessage();}
        catch (Exception exception) {message = FAILED;}

        log.error("路由 : {}，SQLIntegrityConstraintViolationException 错误信息 : {}", request.getRequestURL(), message);

        e.printStackTrace();

        return Result.error(ResultCode.RFC, message);
    }

    /**
     * 处理请求参数格式错误 @RequestBody上validate失败后抛出的异常是MethodArgumentNotValidException异常。
     * @param request
     * @param e
     * @return
     */
    @ExceptionHandler(MethodArgumentNotValidException.class)
    public Result exceptionHander(HttpServletRequest request, MethodArgumentNotValidException e) {
        String message = e.getBindingResult().getAllErrors().stream().map(DefaultMessageSourceResolvable::getDefaultMessage).collect(Collectors.joining(Constants.ERROR_SPLIT));
        log.error("路由 : {}，RequestBody-Valid MethodArgumentNotValidException 错误信息 : {}", request.getRequestURL(), message);

        e.printStackTrace();

        return Result.error(ResultCode.FAILURE, message);
    }

    /**
     * @desc <p> 请求头数据类型不符合 </p>
     * @author ：xi
     * @date 2021/10/1
     */
    @ExceptionHandler(HttpMediaTypeNotSupportedException.class)
    public Result exceptionHander(HttpServletRequest request, HttpMediaTypeNotSupportedException e) {
        String message = "";try {message = e.getMessage();}
        catch (NullPointerException nullPointerException) {message = e.getCause().getMessage();}
        catch (Exception exception) {message = FAILED;}

        log.error("路由 : {}，RequestBody-Valid HttpMediaTypeNotSupportedException 错误信息 : {}", request.getRequestURL(), message);

        e.printStackTrace();

        return Result.error(ResultCode.FAILURE, message);
    }


    /**
     * @desc <p> 请求数据缺少 </p>
     * @author ：xi
     * @date 2021/10/1
     */
    @ExceptionHandler(HttpMessageNotReadableException.class)
    public Result exceptionHander(HttpServletRequest request, HttpMessageNotReadableException e) {
        String message = "";try {message = e.getMessage();}
        catch (NullPointerException nullPointerException) {message = e.getCause().getMessage();}
        catch (Exception exception) {message = FAILED;}

        log.error("路由 : {}，RequestBody-Valid HttpMessageNotReadableException 错误信息 : {}", request.getRequestURL(), message);

        e.printStackTrace();

        return Result.error(ResultCode.FAILURE, message);
    }

    /**
     * 处理Get请求中 使用@Valid 验证路径中请求实体校验失败后抛出的异常，
     * @param request
     * @param e
     * @return
     */
    @ExceptionHandler(BindException.class)
    public Result exceptionHander(HttpServletRequest request, BindException e)  {
        String message = e.getBindingResult().getAllErrors().stream().map(DefaultMessageSourceResolvable::getDefaultMessage).collect(Collectors.joining(Constants.ERROR_SPLIT));
        log.error("路由 : {}，Get-Valid BindException 错误信息 : {}", request.getRequestURL(), message);

        e.printStackTrace();

        return Result.error(ResultCode.FAILURE, message);
    }

    /**
     * 参数注解校验异常
     * @param request
     * @param e
     * @return
     */
    @ExceptionHandler(ConstraintViolationException.class)
    public Result exceptionHander(HttpServletRequest request, ConstraintViolationException e) {
        String message = e.getConstraintViolations().stream().map(ConstraintViolation::getMessage).collect(Collectors.joining(Constants.ERROR_SPLIT));
        log.error("路由 : {}，ConstraintViolationException 错误信息 : {}", request.getRequestURL(), message);

        e.printStackTrace();
        return Result.error(ResultCode.FAILURE.getCode(), message);
    }

    /**
     * 处理Get请求中 使用@Valid 验证路径中请求实体校验失败后抛出的异常，
     * @param request
     * @param e
     * @return
     */
    @ExceptionHandler(NullPointerException.class)
    public Result exceptionHander(HttpServletRequest request, NullPointerException e)  {
        String message = "";try {message = e.getMessage();}
        catch (NullPointerException nullPointerException) {message = e.getCause().getMessage();}
        catch (Exception exception) {message = FAILED;}

        log.error("路由 : {}，NullPointerException 空指针异常错误信息 : {}", request.getRequestURL(), message);

        e.printStackTrace();

        return Result.error(ResultCode.FAILURE, message);
    }

    /**
     * 数据不存在异常
     * @param request
     * @param e
     * @return
     */
    @ExceptionHandler(IllegalArgumentException.class)
    public Result exceptionHander(HttpServletRequest request, IllegalArgumentException e)  {
        String message = "";try {message = e.getMessage();}
        catch (NullPointerException nullPointerException) {message = e.getCause().getMessage();}
        catch (Exception exception) {message = FAILED;}

        log.error("路由 : {}，IllegalArgumentException 空指针异常错误信息 : {}", request.getRequestURL(), message);

        e.printStackTrace();

        return Result.error(ResultCode.NOT_FOUND, message);
    }


    /**
     * 运行时异常
     * @param request
     * @param e
     * @return
     */
    @ExceptionHandler(RuntimeException.class)
    public Result exceptionHander(HttpServletRequest request, RuntimeException e) {
        String message = "";try {message = e.getMessage();}
        catch (NullPointerException nullPointerException) {message = e.getCause().getMessage();}
        catch (Exception exception) {message = FAILED;}

        log.error("路由 : {}，RuntimeException 错误信息 : {}", request.getRequestURL(), message);

        e.printStackTrace();

        return Result.error(ResultCode.FAILURE, message);
    }




    /**
     * 请求方式错误
     * @param request
     * @param e
     * @return
     */
    @ExceptionHandler(HttpRequestMethodNotSupportedException.class)
    public Result exceptionHander(HttpServletRequest request, HttpRequestMethodNotSupportedException e){
        StringBuffer sb = new StringBuffer();
        sb.append("该链接不支持");
        sb.append(e.getMethod());
        sb.append("请求，");
        sb.append("支持以下请求：");
        String[] methods = e.getSupportedMethods();
        if(methods!=null){
            for(String str:methods){
                sb.append(str);
                sb.append("/");
            }
        }
        log.error("路由 : {}，HttpRequestMethodNotSupportedException 错误信息 : {}", request.getRequestURL(), sb);

        e.printStackTrace();

        return Result.error(ResultCode.NOT_ALOW, sb.toString());
    }

    /**
     * spring默认上传大小100MB 超出大小捕获异常MaxUploadSizeExceededException
     */
    @ExceptionHandler(MaxUploadSizeExceededException.class)
    public Result exceptionHander(HttpServletRequest request, MaxUploadSizeExceededException e) {
        String message = "";try {message = e.getMessage();}
        catch (NullPointerException nullPointerException) {message = e.getCause().getMessage();}
        catch (Exception exception) {message = FAILED;}

        log.error("路由 : {}，MaxUploadSizeExceededException 错误信息 : {}", request.getRequestURL(), "文件大小超出限制, 请压缩或降低文件质量!\n " + message);

        e.printStackTrace();

        return Result.error("文件大小超出限制, 请压缩或降低文件质量! \n" + message);
    }



    /**
     * 其它异常
     * @param request
     * @param e
     * @return
     */
    @ExceptionHandler(Exception.class)
    public Result exceptionHander(HttpServletRequest request, Exception e) {
        String message = "";try {message = e.getMessage();}
        catch (NullPointerException nullPointerException) {message = e.getCause().getMessage();}
        catch (Exception exception) {message = FAILED;}

        log.error("路由 : {}，Exception 错误信息 : {}", request.getRequestURL(), message);

        e.printStackTrace();

        return Result.error(ResultCode.FAILURE, "操作失败," + message);
    }
}
